package com.common.account.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.common.account.entity.UserAndMechanism;
import com.common.account.entity.UserAndMechanismDirectlyUnder;
import com.common.account.entity.UserAndRole;
import com.common.account.entity.vo.*;
import com.common.account.service.*;
import com.common.basis.entity.User;
import com.common.basis.oauth.AuUser;
import com.common.basis.result.Result;
import com.common.basis.result.ResultPage;
import com.common.basis.result.ResultSet;
import com.common.basis.util.DesensitizationUtil;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户
 *
 * @author zhengboda
 * @date 2020-01-08 14:39
 **/
@RestController
@AllArgsConstructor
@RequestMapping({"/au-user"})
public class AuUserController {
    private final IAuUserService iAuUserService;
    private final IAuPermissionService iAuPermissionService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;
    private final IUserAndRoleService iUserAndRoleService;
    private final IUserAndMechanismService iUserAndMechanismService;
    private final IUserAndMechanismDirectlyUnderService iUserAndMechanismDirectlyUnderService;
    private final StringRedisTemplate stringRedisTemplate;

    /**
     * 用户查询
     */
    @GetMapping
    public ResultPage<AuUser> findTree(AuUserVo param) {
        LambdaQueryWrapper<AuUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(param.getUserName() != null, AuUser::getUserName, param.getUserName())
                .like(param.getActualName() != null, AuUser::getActualName, param.getActualName())
                .eq(param.getTenantId() != null, AuUser::getTenantId, param.getTenantId())
                .eq(param.getIsAccount() != null, AuUser::getIsAccount, param.getIsAccount())
                .ne(AuUser::getUserName, "admin")
                .orderByDesc(AuUser::getCreated);
        Page<AuUser> page = iAuUserService.page(param.page(), wrapper);
        List<AuUser> records = page.getRecords();
        Set<String> ids = records.stream().map(AuUser::getId).collect(Collectors.toSet());
        if (ids.isEmpty()) {
            return ResultSet.page(page);
        }
        List<UserAndMechanism> mechanismByUserIds = iUserAndMechanismService.getMechanismByUserIds(ids);
        List<UserAndRole> list = iUserAndRoleService.findByUserId(ids);
        for (AuUser record : records) {
            if (!(record.getPhone() == null || "".equals(record.getPhone()))) {
                record.setPhone(DesensitizationUtil.phoneNumber(record.getPhone()));
            }
            if (!(record.getIdentityCard() == null || "".equals(record.getIdentityCard()))) {
                record.setIdentityCard(DesensitizationUtil.idCard(record.getIdentityCard()));
            }
            record.setPassword(null);
            for (UserAndRole userAndRole : list) {
                if (userAndRole.getUserId().equals(record.getId())) {
                    record.setRoleNames(userAndRole.getRoleNames());
                }
            }
            for (UserAndMechanism mechanism : mechanismByUserIds) {
                if (record.getId().equals(mechanism.getAuUserId())) {
                    record.setAuMechanisms(mechanism.getMechanismNames());
                }
            }
        }
        return ResultSet.page(page);
    }

    /**
     * 用户新增
     * 初始密码123456
     */
    @PostMapping()
    public Result<?> post(@RequestBody @Validated AuUser param) {
        String systemUser = "admin";
        if (systemUser.equals(param.getUserName())) {
            return ResultSet.error("无权限操作！");
        }
        LambdaQueryWrapper<AuUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AuUser::getUserName, param.getUserName());
        int count = iAuUserService.count(wrapper);
        if (count > 0) {
            return ResultSet.error("账号重复");
        }
        param.setPassword(bCryptPasswordEncoder.encode("123456"));
        String tenantId = getTenantId();
        param.setTenantId(tenantId);
        boolean b = iAuUserService.save(param);
        return ResultSet.operation(b);
    }

    /**
     * 用户修改
     */
    @PutMapping()
    public Result<?> put(@RequestBody @Validated AuUserVo param) {
        AuUser auUser = new AuUser();
        BeanUtils.copyProperties(param, auUser);
        String systemUser = "admin";
        AuUser byId = iAuUserService.getById(auUser.getId());
        if (systemUser.equals(byId.getUserName())) {
            return ResultSet.error("admin账号不能修改");
        }
        LambdaQueryWrapper<AuUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.ne(AuUser::getId, auUser.getId());
        wrapper.eq(AuUser::getUserName, auUser.getUserName());
        int count = iAuUserService.count(wrapper);
        if (count > 0) {
            return ResultSet.error("账号重复");
        }
        boolean b = iAuUserService.updateById(auUser);
        return ResultSet.operation(b);
    }

    /**
     * 设置开放id
     *
     * @param param 参数
     * @return {@code Result<?>}
     */
    @PutMapping("setOpenId")
    public Result<?> setOpenId(@RequestBody @Validated AuUserVo param) {
        LambdaUpdateWrapper<AuUser> update = Wrappers.lambdaUpdate();
        update.setSql("openId = null")
                .eq(AuUser::getOpenId, param.getOpenId());
        iAuUserService.update(update);
        update.set(AuUser::getOpenId, param.getOpenId())
                .eq(AuUser::getId, param.getId());
        boolean b = iAuUserService.update(update);
        return ResultSet.operation(b);
    }

    /**
     * 删除
     */
    @DeleteMapping()
    @Transactional(rollbackFor = Exception.class)
    public Result<?> del(@RequestParam String id) {
        String systemUser = "admin";
        AuUser byId = iAuUserService.getById(id);
        if (systemUser.equals(byId.getUserName())) {
            return ResultSet.error("admin账号不能修改");
        }
        boolean b = iAuUserService.removeById(id);
        return ResultSet.operation(b);
    }

    /**
     * 重置密码
     */
    @PutMapping("resetPassword")
    public Result<?> resetPassword(@RequestBody @Validated AuUserResetPasswordVo param) {
        LambdaUpdateWrapper<AuUser> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(AuUser::getId, param.getId());
        wrapper.set(AuUser::getPassword, bCryptPasswordEncoder.encode("123456"));
        return ResultSet.operation(iAuUserService.update(wrapper));
    }

    /**
     * 修改密码
     */
    @PostMapping("changePassword")
    public Result<?> changePassword(@RequestBody PasswordVo param,
                                    Authentication authentication) {
        String name = authentication.getName();
        LambdaQueryWrapper<AuUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AuUser::getUserName, name);
        AuUser one = iAuUserService.getOne(wrapper);
        if (!bCryptPasswordEncoder.matches(param.getOldPassword(), one.getPassword())) {
            return ResultSet.error("旧密码错误");
        } else {
            LambdaUpdateWrapper<AuUser> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(AuUser::getId, one.getId());
            updateWrapper.set(AuUser::getPassword, bCryptPasswordEncoder.encode(param.getNewPassword()));
            boolean b = iAuUserService.update(updateWrapper);
            return ResultSet.operation(b);
        }
    }

    /**
     * 设置角色
     */
    @PutMapping("set-role")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> setRole(@RequestBody @Validated SetRoleVo param) {
        List<String> roles = param.getRoleIds();
        List<String> userIds = param.getUserIds();
        ArrayList<UserAndRole> list = new ArrayList<>();
        for (String role : roles) {
            for (String userId : userIds) {
                UserAndRole andRole = new UserAndRole();
                andRole.setUserId(userId);
                andRole.setRoleId(role);
                list.add(andRole);
            }
        }
        LambdaQueryWrapper<UserAndRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(UserAndRole::getUserId, userIds);
        iUserAndRoleService.remove(wrapper);
        return ResultSet.operation(iUserAndRoleService.saveBatch(list));
    }

    /**
     * 设置组织
     *
     * @param param 参数
     * @return 状态
     */
    @PutMapping("mechanism")
    public Result<?> setMechanism(@RequestBody @Validated SetMechanismVo param) {
        List<String> stringList = param.getAuMechanismId();
        List<String> mechanismDirectlyUnderList = param.getAuMechanismDirectlyUnderId();
        String auUserId = param.getAuUserId();
        ArrayList<UserAndMechanism> list = new ArrayList<>();
        for (String s : stringList) {
            UserAndMechanism mechanism = new UserAndMechanism();
            mechanism.setAuMechanismId(s);
            mechanism.setAuUserId(auUserId);
            list.add(mechanism);
        }
        LambdaQueryWrapper<UserAndMechanism> rm = Wrappers.lambdaQuery();
        rm.eq(UserAndMechanism::getAuUserId, auUserId);
        iUserAndMechanismService.remove(rm);
        iUserAndMechanismService.saveBatch(list);
        ArrayList<UserAndMechanismDirectlyUnder> arr = new ArrayList<>();
        for (String s : mechanismDirectlyUnderList) {
            UserAndMechanismDirectlyUnder mechanism = new UserAndMechanismDirectlyUnder();
            mechanism.setAuMechanismId(s);
            mechanism.setAuUserId(auUserId);
            arr.add(mechanism);
        }
        LambdaQueryWrapper<UserAndMechanismDirectlyUnder> rmd = Wrappers.lambdaQuery();
        rmd.eq(UserAndMechanismDirectlyUnder::getAuUserId, auUserId);
        iUserAndMechanismDirectlyUnderService.remove(rmd);
        iUserAndMechanismDirectlyUnderService.saveBatch(arr);
        return ResultSet.success();
    }

    /**
     * 用户登录查询
     *
     * @param userName 用户账号
     * @return 用户信息
     */
    @GetMapping(value = "/get-user-by-name")
    public User getUserByName(@RequestParam String userName) {
        AuUser user = iAuUserService.findUserByName(userName);
//        List<AuPermission> list = iAuPermissionService.findByUserName(userName);
        Set<GrantedAuthority> set = new HashSet<>();
//        for (AuPermission auPermission : list) {
//            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(auPermission.getPermissionCode());
//            set.add(grantedAuthority);
//        }
        User user1 = new User();
        user1.setPassword(user.getPassword());
        user1.setUsername(user.getUserName());
        user1.setAuthorities(new HashSet<>());
        user1.setTenantId(user.getTenantId());
        user1.setUserId(user.getId());
        user1.setAccountNonExpired(true);
        user1.setAccountNonLocked(true);
        user1.setCredentialsNonExpired(true);
        user1.setEnabled(true);
        return user1;
    }

    /**
     * 根据ID查询用户
     */
    @GetMapping("findById")
    public Result<AuUser> findById(@RequestParam("id") String id) {
        AuUser auUser = iAuUserService.getById(id);
        return ResultSet.go(auUser);
    }

    /**
     * 根据ID查询用户
     */
    @GetMapping("findByIds")
    public Result<List<AuUser>> findByIds(@RequestParam List<String> ids) {
        List<AuUser> auUsers = iAuUserService.listByIds(ids);
        return ResultSet.go(auUsers);
    }

    /**
     * 用户详情
     */
    @GetMapping("userDetailsRequest")
    public Result<AuUser> userDetailsRequest(Authentication authentication) {
        String name = authentication.getName();
        AuUser auUser = iAuUserService.findUserByName(name);
        HashSet<String> set = new HashSet<>();
        set.add(auUser.getId());
        List<UserAndRole> roleList = iUserAndRoleService.findByUserId(set);
        for (UserAndRole userAndRole : roleList) {
            if (userAndRole.getUserId().equals(auUser.getId())) {
                auUser.setRoleNames(userAndRole.getRoleNames());
            }
        }
        return ResultSet.go(auUser);
    }


    /**
     * 忘记密码-修改密码
     */
    @PutMapping("forgotPasswordChangePassword")
    public Result<?> forgotPasswordChangePassword(@RequestBody @Validated ForgotPasswordChangePassword param) {
        String verifyByKey = stringRedisTemplate.opsForValue().get(param.getUserName());
        if (verifyByKey == null) {
            return ResultSet.error("没有验证信息");
        } else if (!verifyByKey.equals(param.getVerificationCode())) {
            return ResultSet.error("验证码错误");
        } else {
            LambdaUpdateWrapper<AuUser> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(AuUser::getUserName, param.getUserName());
            updateWrapper.set(AuUser::getPassword, bCryptPasswordEncoder.encode(param.getNewPassword()));
            boolean b = iAuUserService.update(updateWrapper);
            return ResultSet.operation(b);
        }
    }

    /**
     * 查询所有用户(默认当前租户)
     */
    @GetMapping("findAll")
    public Result<List<AuUser>> findAll(@RequestParam Integer isAccount,
                                        @RequestParam(required = false) String userName) {
        LambdaQueryWrapper<AuUser> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(AuUser::getTenantId, getTenantId())
                .eq(AuUser::getEnabled, 0)
                .ne(AuUser::getId, getUserId())
                .like(StringUtils.isNotBlank(userName), AuUser::getUserName, userName)
                .eq(isAccount == null, AuUser::getIsAccount, 0)
                .eq(isAccount != null, AuUser::getIsAccount, isAccount);
        List<AuUser> auUsers = iAuUserService.list(wrapper);
        return ResultSet.go(auUsers);
    }

    /**
     * 得到租户id
     *
     * @return {@code String}
     */
    private String getTenantId() {
        //是否携带参数
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String tenantId = request.getHeader("tenantId");
        //当前登录人租户
        if (StringUtils.isBlank(tenantId)) {
            OAuth2Authentication authentication = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication();
            Authentication userAuthentication = authentication.getUserAuthentication();
            User user = (User) userAuthentication.getPrincipal();
            tenantId = user.getTenantId();
        }
        return tenantId;
    }

    /**
     * 得到登录人用户id
     *
     * @return {@code String}
     */
    private String getUserId() {
        OAuth2Authentication authentication = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication();
        Authentication userAuthentication = authentication.getUserAuthentication();
        User user = (User) userAuthentication.getPrincipal();
        return user.getUserId();
    }

    /**
     * 查询所有用户（根据租户）
     */
    @GetMapping("findAllByTenantId")
    public Result<List<AuUser>> findAllByTenantId(@RequestParam String tenantId) {
        LambdaQueryWrapper<AuUser> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(AuUser::getTenantId, tenantId)
                .eq(AuUser::getEnabled, 0)
                .eq(AuUser::getIsAccount, 0);
        List<AuUser> auUsers = iAuUserService.list(wrapper);
        return ResultSet.go(auUsers);
    }

    /**
     * 发现通过开放id
     * 根据openID获取用户
     *
     * @param openId 开放id
     * @return {@link Result}<{@link User}>
     */
    @GetMapping("findByOpenId")
    public Result<User> findByOpenId(@RequestParam String openId) {
        LambdaQueryWrapper<AuUser> query = Wrappers.lambdaQuery();
        query.eq(AuUser::getOpenId, openId);
        AuUser auUser = iAuUserService.getOne(query, false);
        User user = new User();
        user.setPassword(auUser.getPassword());
        user.setUsername(auUser.getUserName());
        user.setAuthorities(new HashSet<>());
        user.setTenantId(auUser.getTenantId());
        user.setAccountNonExpired(true);
        user.setAccountNonLocked(true);
        user.setCredentialsNonExpired(true);
        user.setEnabled(true);
        return ResultSet.go(user);
    }

    /**
     * 根据用户查询权限
     */
    @GetMapping("permissionByUserId")
    public Result<?> permissionByUserId(@RequestParam String userId) {
        List<String> list = iAuPermissionService.findByUserId(userId);
        return ResultSet.go(list);
    }


}
